package com.wqr.mobile.android.ui.net;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.http.AndroidHttpClient;
import android.util.Log;

import com.wqr.mobile.android.ui.R;

/**
 * 
 * @author wenqiurong
 * 
 */
public class NetworkManager {

	private static final String RESPONSE_ERROR = "error";

	private static final String TAG = NetworkManager.class.getSimpleName();

	private static final String REQUEST_METHOD_POST = "POST";
	private static final String REQUEST_METHOD_GET = "GET";
	private static final String REQUEST_DATA = "requestData";

	private static final String CONTENT_TYPE_KEY = "Content-type";
	private static final String CHARSET = HTTP.UTF_8;

	private static final String CONTENT_TYPE = "application/x-www-form-urlencoded;charset=utf-8";

	private static final String HTTPCLIENT_NAME = "Android";

	private int connectTimeout = 30 * 1000;
	private int readTimeout = 30 * 1000;
	private Proxy mProxy;

	private static NetworkManager instance = new NetworkManager();

	private NetworkManager() {
	};

	/**
	 * get NetworkManager instance
	 * 
	 * @return
	 */
	public static NetworkManager getInstance() {
		return instance;
	}

	/**
	 * request with method=get
	 * 
	 * @param url
	 * @return
	 */
	public String requestGet(String url) {
		return getInputStreamWithGet(url);
	}

	/**
	 * request with method=post
	 * 
	 * @param url
	 * @return
	 */
	// @Deprecated
	// public String requestPost(String url) {
	// return convertStreamToString(getInputStreamWithPost(url));
	// }

	/**
	 * download to file
	 * 
	 * @param url
	 * @param path
	 * @return
	 */
	// public boolean downloadToFile(String url, String path) {
	// return writeStreamToFile(getInputStreamWithPost(url), path);
	// }

	/**
	 * post发送和接收数据
	 * 
	 * @param context
	 * @param strReqData
	 *            请求数据
	 * @param strUrl
	 *            请求地址
	 * @return
	 */
	public String postRequest(Context context, String strReqData, String strUrl) {
		return httpRequest(context, strReqData, strUrl, REQUEST_METHOD_POST);
	}

	/**
	 * post发送和接收数据
	 * 
	 * @param context
	 * @param Parameters
	 *            请求参数列表
	 * @param url
	 * @return
	 */
	public String postRequest(Context context, List<BasicNameValuePair> Parameters, String url) {
		return httpRequest(context, Parameters, url);
	}

	/**
	 * 
	 * @param context
	 * @param strUrl
	 * @return
	 */
	public Bitmap downloadImages(Context context, String image_url) {
		return httpRequest(context, image_url);
	}

	/**
	 * get发送和接收数据
	 * 
	 * @param context
	 * @param strReqData
	 *            请求数据
	 * @param strUrl
	 *            请求地址
	 * @return
	 */
	public String getRequest(Context context, String strReqData, String strUrl) {
		return httpRequest(context, strReqData, strUrl, REQUEST_METHOD_GET);
	}

	/**
	 * 上传文件
	 * 
	 * @param context
	 * @param strReqData
	 * @param strUrl
	 * @return
	 */
	public String postUpload(Context context, String strReqData, String strUrl) {
		return httpRequest(context, strReqData, strUrl, REQUEST_DATA);
	}

	private Bitmap httpRequest(Context context, String strUrl) {
		detectProxy(context);
		Bitmap bitmap = null;
		HttpURLConnection httpConnect = null;
		try {
			URL url = new URL("http://192.168.0.100:8000/image" + File.separator + strUrl);

			if (mProxy != null) {
				httpConnect = (HttpURLConnection) url.openConnection(mProxy);
			} else {
				httpConnect = (HttpURLConnection) url.openConnection();
			}
			httpConnect.setRequestMethod(REQUEST_METHOD_GET);
			httpConnect.setConnectTimeout(connectTimeout);
			httpConnect.setReadTimeout(readTimeout);
			httpConnect.setDoOutput(true);
			httpConnect.addRequestProperty(CONTENT_TYPE_KEY, CONTENT_TYPE);

			httpConnect.connect();
			if (httpConnect.getResponseCode() != HttpURLConnection.HTTP_OK) {
				httpConnect.disconnect();
				httpConnect = null;
				return null;
			}

			BufferedInputStream bis = new BufferedInputStream(httpConnect.getInputStream());
			bitmap = BitmapFactory.decodeStream(bis);
			bis.close();

		} catch (IOException e) {
			Log.e(TAG, "Error while request " + strUrl, e.getCause());
		} finally {
			if (httpConnect != null) {
				httpConnect.disconnect();
				httpConnect = null;
			}
		}

		return bitmap == null ? BitmapFactory.decodeResource(context.getResources(), R.drawable.icon) : bitmap;
	}

	/**
	 * http request
	 * 
	 * @param context
	 * @param strReqData
	 * @param strUrl
	 * @param method
	 *            post get
	 * @return
	 */
	private String httpRequest(Context context, String strReqData, String strUrl, String method) {
		// Log.i(TAG, "resquest-->" + strUrl);
		detectProxy(context);
		String strResponse = null;

		HttpURLConnection httpConnect = null;
		UrlEncodedFormEntity p_entity = null;
		try {
			if (method.equals(REQUEST_DATA)) {
				ArrayList<BasicNameValuePair> pairs = new ArrayList<BasicNameValuePair>();
				pairs.add(new BasicNameValuePair(method, strReqData));
				p_entity = new UrlEncodedFormEntity(pairs, CHARSET);
			}

			URL url = new URL(strUrl);

			if (mProxy != null) {
				httpConnect = (HttpURLConnection) url.openConnection(mProxy);
			} else {
				httpConnect = (HttpURLConnection) url.openConnection();
			}
			httpConnect.setRequestMethod(method);
			httpConnect.setConnectTimeout(connectTimeout);
			httpConnect.setReadTimeout(readTimeout);
			httpConnect.setDoOutput(true);
			httpConnect.addRequestProperty(CONTENT_TYPE_KEY, CONTENT_TYPE);

			httpConnect.connect();
			BufferedOutputStream output = new BufferedOutputStream(httpConnect.getOutputStream());
			if (method.equals(REQUEST_DATA)) {
				p_entity.writeTo(output);
			} else {
				if (strReqData != null) {
					Log.i(TAG, "resquest data-->" + strReqData);
					output.write(strReqData.getBytes());
				}
			}
			output.flush();
			output.close();
			output = null;

			BufferedInputStream bis = new BufferedInputStream(httpConnect.getInputStream());
			strResponse = convertStreamToString(bis);
			// Log.i(TAG, "response-->" + strResponse);
		} catch (IOException e) {
			Log.e(TAG, "Error while request " + strUrl, e.getCause());
		} finally {
			httpConnect.disconnect();
		}

		return strResponse == null ? RESPONSE_ERROR : strResponse.toString();
	}

	/**
	 * 
	 * @param context
	 * @param Parameters
	 *            请求参数列表
	 * @param strUrl
	 * @return
	 */
	private String httpRequest(Context context, List<BasicNameValuePair> Parameters, String strUrl) {
		// Log.i(TAG, "resquest-->" + strUrl);
		detectProxy(context);
		String strResponse = null;

		HttpURLConnection httpConnect = null;
		UrlEncodedFormEntity p_entity = null;
		try {
			p_entity = new UrlEncodedFormEntity(Parameters, CHARSET);

			URL url = new URL(strUrl);

			if (mProxy != null) {
				httpConnect = (HttpURLConnection) url.openConnection(mProxy);
			} else {
				httpConnect = (HttpURLConnection) url.openConnection();
			}
			httpConnect.setRequestMethod(REQUEST_METHOD_POST);
			httpConnect.setConnectTimeout(connectTimeout);
			httpConnect.setReadTimeout(readTimeout);
			httpConnect.setDoOutput(true);
			httpConnect.addRequestProperty(CONTENT_TYPE_KEY, CONTENT_TYPE);

			httpConnect.connect();
			BufferedOutputStream output = new BufferedOutputStream(httpConnect.getOutputStream());
			p_entity.writeTo(output);
			output.flush();
			output.close();
			output = null;

			BufferedInputStream bis = new BufferedInputStream(httpConnect.getInputStream());
			strResponse = convertStreamToString(bis);
			// Log.i(TAG, "response-->" + strResponse);
		} catch (IOException e) {
			Log.e(TAG, "Error while request " + strUrl, e.getCause());
		} finally {
			if (httpConnect != null) {
				httpConnect.disconnect();
			}
		}

		return strResponse == null ? RESPONSE_ERROR : strResponse.toString();
	}

	/**
	 * 检查代理，是否cnwap接入
	 */
	private void detectProxy(Context context) {
		ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo ni = cm.getActiveNetworkInfo();
		if (ni != null && ni.isAvailable() && ni.getType() == ConnectivityManager.TYPE_MOBILE) {
			Log.d(TAG, "detectProxy-->ni:" + ni.toString());
			String proxyHost = android.net.Proxy.getDefaultHost();
			int port = android.net.Proxy.getDefaultPort();
			// Log.d(TAG, "detectProxy-->proxyHost:" + proxyHost != null ? proxyHost.toString() : "null" + ",port:" + port);
			if (proxyHost != null) {
				final InetSocketAddress sa = new InetSocketAddress(proxyHost, port);
				mProxy = new Proxy(Proxy.Type.HTTP, sa);
			}
		}
	}

	/**
	 * get inputstream from url with method=get
	 * 
	 * @param url
	 * @return
	 */
	private String getInputStreamWithGet(String url) {
		InputStream inputStream = null;
		HttpClient httpClient = AndroidHttpClient.newInstance(HTTPCLIENT_NAME);
		try {
			final HttpGet get = new HttpGet(new URI(URLEncoder.encode(url)));
			HttpResponse response = httpClient.execute(get);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				final HttpEntity entity = response.getEntity();
				if (entity != null) {
					inputStream = entity.getContent();
				}
			}
		} catch (IOException e) {
			Log.e(TAG, "Error while request " + url, e.getCause());
		} catch (URISyntaxException e) {
			Log.e(TAG, "Error while request " + url, e.getCause());
		} finally {
			clientclose(httpClient);
		}

		return convertStreamToString(inputStream);
	}

	/**
	 * get inputstream from url method=post
	 * 
	 * @param url
	 * @return
	 */
	private InputStream getInputStreamWithPost(String url) {
		InputStream inputStream = null;
		HttpClient httpClient = AndroidHttpClient.newInstance(HTTPCLIENT_NAME);
		try {
			final HttpPost post = new HttpPost(new URI(URLEncoder.encode(url)));
			HttpResponse response = httpClient.execute(post);
			if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
				final HttpEntity entity = response.getEntity();
				if (entity != null) {
					inputStream = entity.getContent();
				}
			}
		} catch (IOException e) {
			Log.e(TAG, "Error while request " + url, e.getCause());
		} catch (URISyntaxException e) {
			Log.e(TAG, "Error while request " + url, e.getCause());
		} finally {
			clientclose(httpClient);
		}

		return inputStream;
	}

	/**
	 * convert stream to String
	 * 
	 * @param is
	 * @return
	 */
	private String convertStreamToString(InputStream is) {
		StringBuilder sb = null;
		if (is != null) {
			BufferedReader reader = new BufferedReader(new InputStreamReader(is));
			String line = null;
			try {
				sb = new StringBuilder();
				while ((line = reader.readLine()) != null) {
					sb.append(line);
				}
			} catch (IOException e) {
				Log.e(TAG, "Error while convert stream " + is, e.getCause());
			} finally {
				inputStreamclose(is);
			}
		}
		return sb == null ? RESPONSE_ERROR : sb.toString();
	}

	/**
	 * write Stream to file
	 * 
	 * @param is
	 * @param path
	 * @return
	 */
	private boolean writeStreamToFile(InputStream is, String path) {
		boolean flag = false;
		if (is != null) {
			File file = new File(path);
			FileOutputStream fos = null;
			try {
				file.createNewFile();
				fos = new FileOutputStream(file);

				byte[] temp = new byte[1024];
				int i = 0;
				while ((i = is.read(temp)) > 0) {
					fos.write(temp, 0, i);
				}
				flag = true;
			} catch (IOException e) {
				Log.e(TAG, "Error while write Stream to file " + is, e.getCause());
			} finally {
				outputStreamclose(fos);
				inputStreamclose(is);
			}
		}

		return flag;
	}

	/**
	 * close FileOutputStream
	 */
	private void outputStreamclose(OutputStream os) {
		if (os != null) {
			try {
				os.flush();
				os.close();
			} catch (IOException e) {
				Log.e(TAG, "Error while close FileOutputStream " + os, e.getCause());
			}
		}
	}

	/**
	 * close InputStream
	 */
	private void inputStreamclose(InputStream is) {
		if (is != null) {
			try {
				is.close();
			} catch (IOException e) {
				Log.e(TAG, "Error while close InputStream " + is, e.getCause());
			}
		}
	}

	/**
	 * close httpclient
	 */
	private void clientclose(HttpClient httpClient) {
		if (httpClient != null) {
			((AndroidHttpClient) httpClient).close();
		}
	}
}
